package org.chnxi.study.redis.lock;

import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class Lock {

    private final Long defLockTime = 10 * 1000l;

    private final TimeUnit defTimeUnit = TimeUnit.MILLISECONDS;

    private final Long defWaitingTime = 3 * 1000l;

    @Autowired
    private RedissonClient redissonClient;

    public Boolean lock(String lockName){
        if(redissonClient == null){
            throw new IllegalStateException("redissonClient为null，需要被初始化才可使用");
        }

        if(StringUtil.isEmpty(lockName)){
            throw new IllegalArgumentException("加锁操作必须指定锁的名称");
        }

        RLock lock = redissonClient.getLock(lockName);
        lock.lock();
        return !Thread.currentThread().isInterrupted();
    }

    public Boolean unlock(String lockName){
        if(redissonClient == null){
            return false;
        }
        if(StringUtil.isEmpty(lockName)){
            throw new IllegalArgumentException("解锁操作必须指定锁的名称");
        }
        RLock lock = redissonClient.getLock(lockName);
        lock.unlock();
        return lock.getHoldCount() == 0 ? true : false;
    }

    public boolean tryLock(String lockName ,Long waitingTime ,Long lockTime ,TimeUnit timeUnit) throws InterruptedException {
        if(redissonClient == null){
            return false;
        }

        if(StringUtil.isEmpty(lockName)){
            throw new IllegalArgumentException("解锁操作必须指定锁的名称");
        }

        RLock lock = redissonClient.getLock(lockName);

        if(null == timeUnit){
            timeUnit = defTimeUnit;
        }

        if(null == waitingTime || waitingTime < 0){
            waitingTime = timeUnit != defTimeUnit ? timeUnit.convert(defWaitingTime ,defTimeUnit) : defWaitingTime;
        }


        if(null == lockTime || lockTime < 0){
            lockTime = timeUnit != defTimeUnit ? timeUnit.convert(defLockTime ,defTimeUnit) : defLockTime;
        }


        return lock.tryLock(waitingTime , lockTime , timeUnit);
    }

    public boolean tryLock(String lockName) throws InterruptedException {
        return tryLock(lockName , defWaitingTime , defLockTime , defTimeUnit);
    }

    public Boolean tryLock(String lockName , long waitingTime ,TimeUnit timeUnit) throws InterruptedException {
        return tryLock(lockName , waitingTime , null, timeUnit);
    }

}
